package com.cci.kangdao.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.cci.kangdao.aop.UserThreadLocal;
import com.cci.kangdao.dao.*;
import com.cci.kangdao.dao.model.*;
import com.cci.kangdao.redis.RedisClientUtils;
import com.cci.kangdao.service.FaultService;
import com.cci.kangdao.utilTool.*;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @description:
 * @author: shiliqiang
 * @company: CTY Technology Co.,Ltd
 * @since: 2021/7/22 10:16
 * @version: V1.0
 */
@Service
public class FaultServiceImpl implements FaultService {

	private Logger log = Logger.getLogger(this.getClass().getName());

	ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(7, 14, 60, TimeUnit.SECONDS,
			new LinkedBlockingQueue<Runnable>());

	@Autowired
	private FaultDao faultDao;
	@Resource
	private WorkOrderTDao workOrderTDao;

	@Autowired
	private UploadPicturesDao uploadPicturesDao;

	@Resource
	private WorkOrderPictureCategoryTDao workOrderPictureCategoryTDao;

	@Resource
	private WorkOrderPictureDetailTDao workOrderPictureDetailTDao;

	@Resource
	private WorkOrderPicsDao workOrderPicsDao;

	@Autowired
	private CompanyTDao companyTDao;

	@Autowired
	private CRMPlatformServiceDao platformServiceDao;

	@Autowired
	private RedisClientUtils redisClientUtils;

	@Resource
	private ServiceStationDao serviceStationDao;

	@Resource
	private DictionariesTDao dictionariesTDao;

	@Resource
	private OutRangeTDao outRangeTDao;

	@Resource
	private WhiteListTDao whiteListTDao;

	@Resource
	private SSRepairTDao ssRepairTDao;

	@Autowired
	private UploadPicturesImpl uploadPictures;

	@Override
	public List getPictureList(Map<String, Object> map) {
		// HttpServletResponse response = (HttpServletResponse) map.get("response");
		Long orderId = MapUtils.getLong(map, "orderId", 0L);
		String faultId = MapUtils.getString(map, "faultId");
		// 1：DCEC外出，2：DCEC不外出；3：XCEC发动机维修；4：XCEC售时工单；0：其它
		Integer category = MapUtils.getInteger(map, "category", 0);
		// 查询照片的位置 1-维修前；2-维修中；
		Integer position = MapUtils.getInteger(map, "position");
		WorkOrderT workOrderT = workOrderTDao.getWorkOrderTByOrderId(orderId);

		if (null == workOrderT) {
			return null;
		}
		Map<String, Object> data = new HashMap<>(1);

		// 查询订单照片列表
		List<Map<String, Object>> picList = uploadPicturesDao.getPicturesList(map);
		Map<String, Object> dataPictureMap = new LinkedHashMap<>();
		if (CollectionUtils.isNotEmpty(picList)) {
			for (Map<String, Object> dataMap : picList) {
				String picNo = MapUtils.getString(dataMap, "picNo");
				if (StringUtils.isNotEmpty(picNo)) {
					dataPictureMap.put(picNo, dataMap);
				}
			}
		}

		// 获取工单管理类型
		List<Map<String, Object>> categoryList = new ArrayList<>();
		List<WorkOrderPictureCategoryT> categoryTList = workOrderPictureCategoryTDao
				.selectListByChannelId(Long.valueOf(workOrderT.getOrderChannel()), category);
		if (CollectionUtils.isNotEmpty(categoryTList)) {
			for (WorkOrderPictureCategoryT categoryT : categoryTList) {
				// 只查询维修前或维修中的
				if (!categoryT.getPosition().equals(position)) {
					continue;
				}
				Map<String, Object> pictureCategoryMap = new HashMap<>();
				pictureCategoryMap.put("categoryId", categoryT.getId());
				pictureCategoryMap.put("title", categoryT.getTitle());
				pictureCategoryMap.put("orderStatus", categoryT.getOrderStatus());
				List<Map<String, Object>> pictureMapList = new ArrayList<>();
				List<WorkOrderPictureDetailT> workOrderPictureDetailTList = workOrderPictureDetailTDao
						.selectListByCategoryId(categoryT.getId());
				if (CollectionUtils.isNotEmpty(workOrderPictureDetailTList)) {
					for (WorkOrderPictureDetailT detailT : workOrderPictureDetailTList) {
						Map<String, Object> mergeMap = new HashMap<>();
						mergeMap.put("requiredShooting", detailT.getRequiredShooting());
						mergeMap.put("isRequired", detailT.getIsRequired());
						mergeMap.put("isSupplement", detailT.getIsSupplement());
						mergeMap.put("samplePicture", detailT.getSamplePicture());
						mergeMap.put("sampleThumbnailPicture", detailT.getSampleThumbnailPicture());
						mergeMap.put("version", detailT.getVersion());
						mergeMap.put("accessory", detailT.getAccessory());
						mergeMap.put("installDebug", detailT.getInstallDebug());
						mergeMap.put("builtinSoftware", detailT.getBuiltinSoftware());
						mergeMap.put("typeStr",detailT.getTypeStr());
						mergeMap.put("limitationNum",this.uploadPictures.isWhite(workOrderT.getOrderChannel(), workOrderT.getServiceStationId())?detailT.getLimitationNum():0);
						String picNo = detailT.getPictureNo();
						// 如果是维修中且故障唯一识别号不为空时，必定是新功能新数据，维修中faultId为空是老数据
						if (position == 2 && StringUtils.isNotEmpty(faultId)) {
							picNo = picNo + "-" + faultId;
						}
						if (!NumberUtils.isPositiveNum(detailT.getIsSupplement())) {
							// 普通业务照片
							mergeMap.put("picNo", splitPicNo(picNo));
							mergeMap.put("title", detailT.getPictureTitle());
							mergeMap.put("description", detailT.getPictureDesc());
							Map<String, Object> dataPic = (Map<String, Object>) MapUtils.getObject(dataPictureMap,
									picNo);
							if (MapUtils.isNotEmpty(dataPic)) {
								String url = MapUtils.getString(dataPic, "picUrl");
								mergeMap.put("pictureUrl", url);
							} else {
								mergeMap.put("pictureUrl", "");
							}
							pictureMapList.add(mergeMap);
						} else {
							// 其他图片
							String prefix = detailT.getPictureNo();
							List<String> otherPictureNo = new ArrayList<>();
							for (String key : dataPictureMap.keySet()) {
								if (key.startsWith(prefix)) {
									if (StringUtils.isNotEmpty(faultId)) {
										// 如果是其他照片，则把picNo中的时间戳截取出来，和故障id比较
										if (faultId.equals(splitPicNoReturnSystemTime(key))) {
											otherPictureNo.add(key);
										}
									} else {
										otherPictureNo.add(key);
									}

								}
							}
							if (CollectionUtils.isNotEmpty(otherPictureNo)) {
								// 存在其他照片
								for (String key : otherPictureNo) {
									Map<String, Object> dataOtherPictureMap = (Map<String, Object>) MapUtils
											.getObject(dataPictureMap, key);
									Map<String, Object> otherPictureMap = (Map<String, Object>) BeanUtils
											.deepClone(mergeMap);
									String url = MapUtils.getString(dataOtherPictureMap, "picUrl");
									String pictureNo = MapUtils.getString(dataOtherPictureMap, "picNo");
									String description = MapUtils.getString(dataOtherPictureMap, "description");
									otherPictureMap.put("pictureUrl", url);
									otherPictureMap.put("picNo", splitPicNo(pictureNo));
									otherPictureMap.put("title", description);
									otherPictureMap.put("description", description);
									pictureMapList.add(otherPictureMap);
								}
							} else {
								// 不存在其他照片
								continue;
							}
						}

					}
				}
				pictureCategoryMap.put("orderPicture", pictureMapList);
				categoryList.add(pictureCategoryMap);
			}
			return categoryList;
		} /*
		 * else { data.put("pictureList", new ArrayList<>(0)); }
		 */
		return new ArrayList<>(0);
	}

	private String splitPicNo(String picNo) {
		if (picNo.contains("-")) {
			String[] arr = picNo.split("-");
			return arr[0];
		}
		return picNo;
	}

	private String splitPicNoReturnSystemTime(String picNo) {
		if (picNo.contains("-")) {
			String[] arr = picNo.split("-");
			return arr[1];
		}
		return picNo;
	}

	@Override
	public Integer isFinish(Map<String, Object> map) {
		return null;
	}

	@Override
	public Map<String, Object> repairIsFinish(Map<String, Object> map) {
		Map<String, Object> data = new HashMap<>();
		data.put("isFinish", 0);
		Long orderId = MapUtils.getLong(map, "orderId");
		// 1：DCEC外出，2：DCEC不外出；3：XCEC发动机维修；4：XCEC售时工单；0：其它;8：DCEC AMT外出，9：DCEC AMT不外出
		Integer category = MapUtils.getInteger(map, "category", 0);
		// 查询照片的位置 1-维修前；2-维修中；
		Integer position = MapUtils.getInteger(map, "position");
		WorkOrderT workOrderT = workOrderTDao.getWorkOrderTByOrderId(orderId);

		if (null == workOrderT) {
			return data;
		}
		// 查询订单照片列表
		List<Map<String, Object>> picList = uploadPicturesDao.getPicturesList(map);
		Map<String, Object> dataPictureMap = new LinkedHashMap<>();
		if (CollectionUtils.isNotEmpty(picList)) {
			for (Map<String, Object> dataMap : picList) {
				String picNo = MapUtils.getString(dataMap, "picNo");
				if (StringUtils.isNotEmpty(picNo)) {
					dataPictureMap.put(picNo, dataMap);
				}
			}
		}
		// 查询故障信息
		List<JSONObject> faultObjList = faultDao.getFaults(orderId);

		// 超出距离，则判断是否有申请，申请的状态。
		OutRangeT outRangeT = outRangeTDao.getOutRangeTByOrderId(orderId);
		if (outRangeT == null) {// 超出距离，没有申请
			ServiceStationT serviceStation = serviceStationDao.getSSById(workOrderT.getServiceStationId());
			String stationLonLat = "";
			double serviceScope = 0.0;
			boolean outRange = false;// 是否超出距离
			if (category == 2 || category == 9) {// DCEC的站内单判断距离是否超限
				serviceScope = Double.valueOf(dictionariesTDao.getDictionariesListByDTableName("ServiceScope").get(0)
						.getOrDefault("DValue", "0").toString());
				String positionLat = serviceStation.getPositionLat();
				String positionLon = serviceStation.getPositionLon();
				stationLonLat = positionLon + "," + positionLat;
			}
			if (CollectionUtils.isNotEmpty(picList)) {
				for (Map<String, Object> dataMap : picList) {
					if (category == 2 || category == 9 && !outRange) {
						Float locLon = MapUtils.getFloat(dataMap, "LocLon");
						Float locLat = MapUtils.getFloat(dataMap, "LocLat");
						String FaultLonLat = locLon + "," + locLat;
						Double distance = GetDistance.getLineDistance(stationLonLat, FaultLonLat,0);
						if (distance > serviceScope) {
							outRange = true;
						}
					}
				}
			}
			if (category == 2 || category == 9) {// DCEC的站内单判断距离是否超限
				// 参与超距离审批的省份
				String allowProvince = dictionariesTDao.getListByDTableName("allowScopeProvince");
				List<String> allowProvinceList = JSON.parseArray(allowProvince, String.class);
				if (allowProvinceList != null && allowProvinceList.size() > 0) {
					if (!allowProvince.contains(serviceStation.getProvince())) {
						// 不在设置省份内的不参与电子围栏功能
						outRange = false;
					}
				}
				if (outRange) {
					// 非质量索赔的工单无需电子围栏限制
					if (!"1".equals(workOrderT.getNatureClaim())) {
						outRange = false;
					}
				}
			}
			//获取白名单

			//先获取服务站的编号
			List<Map<String, Object>> ssRepairTByServiceStationID = ssRepairTDao.getSSRepairTByServiceStationID(serviceStation.getId());
			if (com.cci.kangdao.utilTool.CollectionUtils.isNotEmpty(ssRepairTByServiceStationID)) {
				String BusinessNo = (String) ssRepairTByServiceStationID.get(0).get("BusinessNo");
				List<WhiteListT> listByType = whiteListTDao.getListByType(4);
				for (WhiteListT whiteListT : listByType) {
					String content = whiteListT.getContent();
					JSONObject jsonObject = JSONObject.parseObject(content);
					String BusinessNoObj = jsonObject.getString("BusinessNo");
					if (BusinessNo.equals(BusinessNoObj)) {
						String StartTime = jsonObject.getString("StartTime");
						String EndTime = jsonObject.getString("EndTime");
						String realCurrentTime = LocalTimeUtil.getRealCurrentTime();
						if (LocalTimeUtil.isBefore(StartTime, realCurrentTime) && LocalTimeUtil.isBefore(realCurrentTime, EndTime)) {
							outRange = false;
							break;
						}
					}
				}
			}

			// 未超出距离
			data.put("isOutRange", 1);
			// DCEC的站内单判断距离是否超限
			if ((category == 2 || category == 9) && outRange) {
				// isOutRange 是否超出距离，0超出距离，1未超出、2审核中、3审核通过（新增字段）
				data.put("isOutRange", 0);
			}
		} else {
			// 申请状态标记10、待一网站长审核20、待区域经理审核30、终审通过40、一网站长审核不通过50、区域经理审核不通过
			// 审核不通过就直接关闭工单了，app端该工单状态已经是关闭状态，因此不需要考虑不通过的情况
			// 是否超出距离，0超出距离，1未超出、2审核中、3审核通过（新增字段）
			data.put("isOutRange", outRangeT.getStatus() == 30 ? 3 : 2);
			data.put("outRangeId", outRangeT.getId());
		}

		// 如果故障类型为空，说明没有故障信息，没有故障信息就没有照片，可能是用户第一次编辑，所以直接返回
		if (position == 2) {
			if (faultObjList == null || faultObjList.size() <= 0) {
				return data;
			}
		}

		// 获取工单管理类型
		List<WorkOrderPictureCategoryT> categoryTList = workOrderPictureCategoryTDao
				.selectListByChannelId(Long.valueOf(workOrderT.getOrderChannel()), category);
		if (CollectionUtils.isNotEmpty(categoryTList)) {
			for (WorkOrderPictureCategoryT categoryT : categoryTList) {
				// 只查询维修前或维修中的
				if (!categoryT.getPosition().equals(position)) {
					continue;
				}
				List<WorkOrderPictureDetailT> workOrderPictureDetailTList = workOrderPictureDetailTDao
						.selectListByCategoryId(categoryT.getId());
				if (CollectionUtils.isNotEmpty(workOrderPictureDetailTList)) {
					for (WorkOrderPictureDetailT detailT : workOrderPictureDetailTList) {
						// 0-非必传照片；1-必填照片
						Integer isRequired = detailT.getIsRequired();
						// 配件故障是否必填0-非必传照片；1-必填照片
						Integer accessory = detailT.getAccessory();
						// 刷标定故障是否必填0-非必传照片；1-必填照片
						Integer builtinSoftware = detailT.getBuiltinSoftware();
						// 装调故障否必填0-非必传照片；1-必填照片
						Integer installDebug = detailT.getInstallDebug();
						String picNo = detailT.getPictureNo();
						// 判断是否为必填照片，如果是必填照片url不能为空（picNo 不带“-故障id”的都是旧数据）
						Map<String, Object> dataPic = (Map<String, Object>) dataPictureMap.get(picNo);
						if (MapUtils.isNotEmpty(dataPic)) {
							if (1 == isRequired) {
								String url = MapUtils.getString(dataPic, "picUrl");
								if (StringUtils.isEmpty(url)) {
									return data;
								}
							}
							continue;
						} else {
							if (position == 1 && 1 == isRequired) {
								return data;
							}
							// 找出能匹配上的key
							List<String> otherPictureNo = dataPictureMap.keySet().stream()
									.filter(key -> key.startsWith(picNo + "-")).collect(Collectors.toList());
							// 只要有一个故障类型的照片是必填，且根据当前picNo查不到数据，返回有未填照片标识，不具体指定哪张未填
							// 根据故障类型判断是否必填
							for (Map<String, Object> faultMap : faultObjList) {
								String faultType = (Integer) faultMap.get("faultType") + "";
								String faultId = (String) faultMap.get("faultId");
								String newPicNo = picNo + "-" + faultId;
								if ("0".equals(faultType)) {
									if ("1".equals(accessory + "")) {
										if (getPictrueIsNull(otherPictureNo, dataPictureMap, newPicNo) == 0) {
											return data;
										}
									}
								} else if ("1".equals(faultType)) {
									if ("1".equals(installDebug + "")) {
										if (getPictrueIsNull(otherPictureNo, dataPictureMap, newPicNo) == 0) {
											return data;
										}
									}
								} else if ("2".equals(faultType)) {
									if ("1".equals(builtinSoftware + "")) {
										if (getPictrueIsNull(otherPictureNo, dataPictureMap, newPicNo) == 0) {
											return data;
										}
									}
								}
							}
						}

					}
				}
			}
		}
		data.put("isFinish", 1);
		return data;
	}

	/**
	 * @description:统一判断是照片是否为空
	 * @param:
	 * @return:
	 * @exception:
	 * @author: shiliqiang
	 * @company: CTY Technology Co.,Ltd
	 * @since: 2021/8/4 16:06
	 * @version: V1.0
	 */
	private Integer getPictrueIsNull(List<String> otherPictureNo, Map<String, Object> dataPictureMap, String newPicNo) {
		// 首先判断上传的照片中是否包含故障信息表中的故障id+picno
		if (!otherPictureNo.contains(newPicNo)) {
			return 0;
		}
		if (CollectionUtils.isEmpty(otherPictureNo)) {
			return 0;
		} else {
			// 遍历当前picNo下所有的数据是否有照片，如果照片为空则直接告诉前端
			for (String key : otherPictureNo) {
				Map<String, Object> dataPic1 = (Map<String, Object>) dataPictureMap.get(key);
				if (MapUtils.isNotEmpty(dataPic1)) {
					String url = MapUtils.getString(dataPic1, "picUrl");
					// 故障类型，0-零件故障；1-装调故障；2-刷标定
					// Integer faultType = (Integer) dataPic1.get("faultType");
					if (StringUtils.isEmpty(url)) {
						return 0;
					}
				} else {
					return 0;
				}
			}
		}
		return 1;
	}

	@Override
	public Integer deleteFaultPicture(String picNo, Long orderId, int flag) {
		// 把故障信息对应的照片更新为不显示
		UserT userT = UserThreadLocal.get();
		return workOrderPicsDao.deteleFaultPicture(orderId, picNo, userT.getId(), LocalTimeUtil.getRealCurrentTime(),
				flag);
	}

	@Override
	public Integer updateFault(Map<String, Object> map) {
		return faultDao.updateFault(map);
	}

	@Override
	public Integer saveFaultInfo(List<JSONObject> list, Long orderId) {
		List<JSONObject> insterList = new ArrayList<>();
		long userId = UserThreadLocal.get().getId();
		String nowTime = LocalTimeUtil.getRealCurrentTime();
		int result = -1;
		for (JSONObject obj : list) {
			int isUpdate = obj.getInteger("isUpdate");
			// 是否更新标识，0新增，1更新，默认0
			if (isUpdate == 1) {
				try {
					obj.put("updator", userId);
					obj.put("updateTime", nowTime);
					obj.put("orderId", orderId);
					result = updateFault((Map) obj);
				} catch (Exception e) {
					log.error(e);
				}
			} else {
				obj.put("flag", 0);
				insterList.add(obj);
			}
		}

		if (insterList == null || insterList.size() <= 0) {
			return result;
		}
		result = faultDao.insertFault(insterList, orderId, nowTime, userId);
		if (result > 0) {
			// 把故障信息同步给CRM
			ThreadHandlerUtil task = new ThreadHandlerUtil(list, orderId, workOrderTDao, companyTDao,
					platformServiceDao, redisClientUtils);
			threadPoolExecutor.execute(task);
		}
		return result;
	}

	@Override
	public List<JSONObject> getFaultInfo(Long orderId) {
		return faultDao.getFaults(orderId);
	}
}
